#include <fcntl.h>
#include <unistd.h>

#include <mutex>
#include <sstream>

#include "debug.hpp"
#include "misc.hpp"
#include "sharedMem.hpp"

semaphore :: semaphore( const std::string& name , bool svr ):
	m_name__( name ), p_sem__( nullptr )
{
	if( svr ){
		p_sem__ = sem_open( name.c_str() , O_CREAT | O_EXCL, 0666 , 1 );
	}else{
		p_sem__ = sem_open( name.c_str() , 0 );
	}
	if( !p_sem__ ){
		const char * msg = strerror( errno );
		if( msg ){
			std::string str( msg );
			throw std::runtime_error( msg );
		}else{
			throw std::runtime_error( "创建信号量失败" );
		}
	}
}

semaphore :: ~semaphore()
{
	MSG( "关闭共享内存" , TNORMAL );
	std::lock_guard< std::mutex >   lck( m_mutex__ );
	if( p_sem__ ){
		sem_close( p_sem__ );
		sem_unlink( m_name__.c_str() );
	}
}

bool semaphore :: lock( bool sw )
{
	std::lock_guard< std::mutex >  lck( m_mutex__ );
	int rc = 0;
	if( sw ){
		rc = sem_wait( p_sem__ );
	}else{
		rc = sem_post( p_sem__ );
	}

	if( rc ){
		ERROR_MSG( strerror( errno ) );
		return false;
	}

	return true;
}

bool semaphore :: tryLock( bool sw )
{
	std::lock_guard< std::mutex >  lck( m_mutex__ );
	int rc = 0;
	if( sw ){
		rc = sem_trywait( p_sem__ );
	}else{
		rc = sem_post( p_sem__ );
	}

	if( rc ){
		ERROR_MSG( strerror( errno ) );
		return false;
	}

	return true;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
smfLockGuard :: smfLockGuard( semaphore& sm ): m_sem__( sm )
{
	sm.lock( true );
}

smfLockGuard :: ~smfLockGuard()
{
	m_sem__.unlock();
}

////////////////////////////////////////////////////////////////////////////////////////////////////
sharedMem :: sharedMem( const std::string& name , uint64_t size , bool svr ):
	m_name__( name ) ,
	m_size__( size ) ,
	m_data_len__( 0 ),
	m_smf__ ( name + "_smf" , svr ),
	m_fd__( -1 )
{
	if( svr ){
		m_fd__ = shm_open( name.c_str() , O_CREAT | O_RDWR , 0666 );
	}else{
		m_fd__ = shm_open( name.c_str() , O_RDWR , 0666 );
	}
	
	if( m_fd__ < 0 ){
		throw std::runtime_error( strerror( errno ));
	}

	ftruncate( m_fd__ , size );

	p_shared_mem__ = ( uint8_t * )mmap( NULL , size , PROT_READ | PROT_WRITE , MAP_SHARED , m_fd__ , 0 );
	if( !p_shared_mem__ ){
		throw std::runtime_error( "将共享内存映射到本地内存失败" );
	}
}

sharedMem :: ~sharedMem()
{
	smfLockGuard lck( m_smf__ );

	close( m_fd__ );
	shm_unlink( m_name__.c_str() );
}

size_t sharedMem :: send( const uint8_t * data ,size_t len )
{
	smfLockGuard lck( m_smf__ );
	std::stringstream ss;
	if( len < m_size__ ){
		m_data_len__ = len;
		ss << m_data_len__ << ",";
		std::string str = ss.str();
		memcpy( p_shared_mem__ , str.c_str() , str.length() );
		memcpy( p_shared_mem__ + str.length() , data , len );
	}else{
		m_data_len__ = len;
		ss << m_data_len__ << ",";
		std::string str = ss.str();
		m_data_len__ = m_size__ - str.length();
		memcpy( p_shared_mem__ + str.length(), data , m_data_len__ );
		
	}

	return m_data_len__;
}

size_t sharedMem :: recv( uint8_t * data , size_t len )
{
	smfLockGuard lck( m_smf__ );
	char * s = ( char *)p_shared_mem__;
	char * e = strstr( s , "," );
	std::string str( s , e - s );

	std::stringstream ss;
	ss << str;
	ss >> m_data_len__;

	if( len > m_data_len__ ){
		memcpy( data , p_shared_mem__ + str.length() + 1, m_data_len__ );
		return m_data_len__;
	}
	memcpy( data , p_shared_mem__ + str.length() + 1 , len );
		
	return len;
}
